#ifndef MINIBSPLINECURVE_H
#define MINIBSPLINECURVE_H

#include "MiniObject.h"

namespace XYF
{
    /**
     * @file: MiniBSplineCurve.h
     * @author: xingyifan
     * @date: 2023-03-12 16:04
     *
     * @description: B 样条曲线类
     */

    class MiniBSplineCurve : public MiniObject
    {
    public:
        // 标准构造函数
        MiniBSplineCurve(const MiniArray<Vector3f> &cpts,
                         const MiniArray<Real> &knots,
                         const int degree,
                         const bool periodic = false);

        // 构造均匀样条
        MiniBSplineCurve(const int N,
                         const int degree,
                         const bool periodic = false);

        // 重载返回类型
        virtual int GetType() override;

        int GetPointsNum() const;                     // 获得顶点数
        const MiniArray<Vector3f> &GetPoints() const; // 获得顶点数组的引用
        MiniArray<Vector3f> &GetPoints();             // 获得顶点数组
        int GetDegree() const;                        // 曲线次数
        bool GetPeriodic() const;                     // 是否是周期函数
        MiniArray<Real> GetKnots() const;             // 获得节点向量
        MiniArray<Real> &GetKnots();                  // 获得节点向量
        Real GetBegin() const;                        // 获得起始位置参数
        Real GetEnd() const;                          // 获得结束位置参数

        Vector3f CurvePoint(Real u) const;                                 // 计算参数 u 处的点
        MiniArray2D<Vector3f> CurveDerivCpts(int d, int r1, int r2) const; // 计算不大于 d 阶导数的控制点，r1,r2 为索引范围
        MiniArray<Vector3f> CurveDerivPoint(int d, Real u) const;          // 计算不大于 d 阶导数曲线在 u 处的点

        void CurveKnotIns(Real u, int r);                // 节点插入算法：将 u 插入 r 次
        void CurveRefineKnot(const MiniArray<Real> &X);  // 节点优化算法：将递增序列 X 中的节点插入
        Real NearPointProjection(Vector3f P, Real tol);  // 返回 P 在曲线上的最近距离投影点的参数，误差不大于 tol
        Real OrthoPointProjection(Vector3f P, Real tol); // 返回 P 在曲线上的正交投影，误差不超过 tol

    protected:
        MiniArray<Vector3f> m_cpts; // 保存点的数组
        MiniArray<Real> m_knots;    // 节点向量
        int m_degree;               // 次数
        bool m_periodic;            // 是否是周期
    };
}

#endif // MINIBSPLINECURVE_H
